package life.system.search.service.impl;

import com.alibaba.fastjson.JSON;
import life.system.common.constant.EsConstant;
import life.system.common.to.es.SkuEsModel;
import life.system.search.config.ElasticSearchConfig;
import life.system.search.service.ElasticsearchService;
import life.system.search.vo.SearchParam;
import life.system.search.vo.SearchResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service("productSaveService")
public class ElasticsearchServiceImpl implements ElasticsearchService {

    @Autowired
    RestHighLevelClient client;


    public boolean productStatusUp(SkuEsModel skuEsModel) throws IOException {
        // 保存到ES
        // 1、给es中建立索引、product，建立映射关系

        // 2、给es中保存这些数据【使用bulk，不使用index一条条保存】
        // BulkRequest bulkRequest, RequestOptions options
        BulkRequest bulkRequest = new BulkRequest();
        // 构造保存请求，设置索引+id
        IndexRequest indexRequest = new IndexRequest(EsConstant.PRODUCT_INDEX);
        indexRequest.id(skuEsModel.getId().toString());
        String s = JSON.toJSONString(skuEsModel);
        // 绑定请求与数据
        indexRequest.source(s, XContentType.JSON);
        // 添加到批量保存
        bulkRequest.add(indexRequest);
        BulkResponse bulk = client.bulk(bulkRequest, ElasticSearchConfig.COMMON_OPTIONS);

        // 如果批量错误
        boolean b = bulk.hasFailures();
        List<String> collect = Arrays.stream(bulk.getItems()).map(BulkItemResponse::getId).collect(Collectors.toList());
        log.info("商品上架完成：{},返回数据：{}", collect, bulk);

        return !b;// 因为b代表的是是否有异常
    }


    /**
     * 删除数据
     */
    public boolean productDel(Integer skuId) throws IOException {
        DeleteRequest request = new DeleteRequest(EsConstant.PRODUCT_INDEX, skuId.toString());
        DeleteResponse deleteResponse = client.delete(request, ElasticSearchConfig.COMMON_OPTIONS);
        return deleteResponse.status().getStatus() == RestStatus.OK.getStatus();
    }

    /**
     * 在es检索
     *
     * @param param 检索的所有参数
     * @return 返回的结果
     */
    public SearchResult search(SearchParam param) {
        SearchResult result = null;
        // 1、动态构建检索需要的DSL语句

        // 1、准备检索请求
        SearchRequest searchRequest = buildSearchRequest(param);
        try {
            // 2、执行检索请求
            SearchResponse searchResponse = client.search(searchRequest, ElasticSearchConfig.COMMON_OPTIONS);

            // 3、分析响应数据，封装成需要的格式
            result = buildSearchResponse(param, searchResponse);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }


    private SearchRequest buildSearchRequest(SearchParam param) {
        // 构建DSL语句对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        /*
         * 模糊匹配，过滤（分类，城市名称，）
         */
        // 1、构建bool - query
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        // 1.1、must【得分】 分词匹配skuTitle
        if (!StringUtils.isEmpty(param.getKeyword())) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("title", param.getKeyword()));
        }

        // 1.2 filter 城市过滤
        if (param.getCityName() != null){
            boolQueryBuilder.filter(QueryBuilders.termQuery("cityName", param.getCityName()));
        }

        // 1.3 filter 分类过滤
        if (param.getSortId() != null){
            boolQueryBuilder.filter(QueryBuilders.termQuery("sortId", param.getSortId()));
        }


        // 1、END 封装查询条件
        sourceBuilder.query(boolQueryBuilder);

        /*
         * 排序，分页，高亮
         */
        // 2.1、排序
        if (!StringUtils.isEmpty(param.getSort())) {
            String[] s = param.getSort().split("_");
            SortOrder order = s[1].equalsIgnoreCase("asc") ? SortOrder.ASC : SortOrder.DESC;
            sourceBuilder.sort(s[0], order);
        }

        // 2.2、分页
        sourceBuilder.from((param.getPageNum() - 1) * EsConstant.PRODUCT_PAGESIZE);
        sourceBuilder.size(EsConstant.PRODUCT_PAGESIZE);


        // 3.2、分类聚合
//        TermsAggregationBuilder catalog_agg = AggregationBuilders.terms("catalog_agg").field("catalogId").size(20);
//        // 子聚合，获得分类名
//        catalog_agg.subAggregation(AggregationBuilders.terms("catalog_name_agg").field("catalogName").size(1));
        // 构建DSL
        //  聚合分类
        //sourceBuilder.aggregation(catalog_agg);

        return new SearchRequest(new String[]{EsConstant.PRODUCT_INDEX}, sourceBuilder);
    }

    /**
     * 封装检索结果
     * 1、返回所有查询到的商品
     * 2、当前所有商品涉及到的所有属性信息
     * 3、当前所有商品涉及到的所有品牌信息
     * 4、当前所有商品涉及到的所有分类信息
     * 5、分页信息   pageNum:当前页码  total:总记录数    totalPages: 总页码
     */
    private SearchResult buildSearchResponse(SearchParam param, SearchResponse searchResponse) {
        SearchResult result = new SearchResult();
        SearchHits hits = searchResponse.getHits();

        // 1、返回所有查询到的商品
        List<SkuEsModel> products = new ArrayList<>();
        if (!ArrayUtils.isEmpty(hits.getHits())) {
            for (SearchHit hit : hits.getHits()) {
                String jsonStr = hit.getSourceAsString();
                SkuEsModel model = JSON.parseObject(jsonStr, SkuEsModel.class);
                products.add(model);
            }
        }
        result.setProducts(products);


        // 5、分页信息   pageNum:当前页码 、total:总记录数 、totalPages: 总页码
        long total = hits.getTotalHits().value;
        int totalPages = (int) total % EsConstant.PRODUCT_PAGESIZE == 0 ? (int) total / EsConstant.PRODUCT_PAGESIZE : ((int) total / EsConstant.PRODUCT_PAGESIZE + 1);
        result.setPageNum(param.getPageNum());
        result.setTotal(total);
        result.setTotalPages(totalPages);

        List<Integer> pageNavs = new ArrayList<>();
        for (int i = 1; i <= totalPages; i++) {
            pageNavs.add(i);
        }
        result.setPageNavs(pageNavs);

        return result;
    }


}

